<template lang="pug">
    .trend
        .trend__chart
            Spin(size="large", fix, v-if="spinShow")
            svg(:width="outerWidth", :height="outerHeight", ref="trend")
                defs
                    clipPath#view
                        rect(:width="width - 1", :height="height - 1", x="1", y="0")
                g(:transform="'translate(' + padding.left + ','+padding.top+')'", ref="stage")
                    rect(ref="stageView", :width="width", :height="height", stroke="#000", fill-opacity="0", pointer-events="all")
                g.legends(:transform="'translate(' + padding.left + ', 10)'")
                    g(v-for="(channel,index) in channels", :class="'channel_' + channel", :transform="'translate(' + (index*width/channels.length) + ',' + '5)'")
                        rect(width="10", height="10", :fill="selectedChannel === channel ? colorScale(channel):'grey'", x="20", @click="changeChannel(channel)")
                        text(x="40", y="9") {{ channel }}
                g.xAxis(:transform="'translate('+ padding.left + ',' + (padding.top + height) + ')'", ref='gRow')
                g.yAxis(:transform="'translate(' + padding.left + ','+padding.top+')'", ref="gSpeed")
                g.xBrush(:transform="'translate(' + (padding.left) + ','+(padding.top+height) +')'", ref="brushX")
                g.yBrush(:transform="'translate(' + (padding.left - brushWidth) + ',' + (padding.top) + ')'", ref="brushY")
                g(:transform="'translate(' + padding.left + ','+padding.top+')'", clip-path="url(#view)")
                    g(v-for="d in data", class="trend-group", :sng="d.type",:fill="colorScale(d.type)",
                    :transform="'translate(' + transform.tx + ',' + transform.ty + ') '+ 'scale(' + transform.sx + ',' + transform.sy + ')'")
                        path(:d="areaGen(d.rows)", class="trend-area", stroke-width="0.5", stroke-opacity="0.5", fill-opacity="0.25", :stroke="colorScale(d.type)")
                        path(:d="lineGen(d.rows)", class="trend-line", :stroke="colorScale(d.type)", stroke-width="1", fill="none")
                    g(class="curve-group"
                    :transform="'translate(' + transform.tx + ',' + transform.ty + ') '+ 'scale(' + transform.sx + ',' + transform.sy + ')'")
                        path(:d="lineGen2(lineData)", stroke="red", stroke-width="1", fill="none")
</template>

<script>
import * as d3 from 'd3';
import { clusterSort } from '@/utils/arrObj';
import { mapState } from 'vuex';

export default {
    data() {
        return {
            spinShow: false,
            outerWidth: 980,
            brushWidth: 15,
            outerHeight: 430,
            padding: { left: 40, right: 20, top: 40, bottom: 20 },
            colorScale: null,
            rowScale: null,
            channelScale: {
                speed: d3.scaleLinear().domain([0, 3000]),
                i30: d3.scaleLinear().domain([0, 2000]),
                i50: d3.scaleLinear().domain([0, 3]),
                u30: d3.scaleLinear().domain([0, 30]),
                u45: d3.scaleLinear().domain([0, 30]),
                u50: d3.scaleLinear().domain([0, 30])
            },
            xBrushScale: null,
            yBrushScale: null,
            // 趋势图数据
            data: [],
            // 普通曲线数据
            lineData: [],
            channels: ['speed', 'i30', 'i50', 'u30', 'u45', 'u50'],
            selectedChannel: 'speed',
            // 生成器
            areaGen: d3.area(),
            lineGen: d3.line(),
            lineGen2: d3.line(),
            // 轴线
            rowAxis: null,
            channelAxis: null,
            zoom: d3.zoom(),
            transform: { tx: 0, ty: 0, sx: 1, sy: 1 }
        };
    },
    computed: {
        width() {
            return this.outerWidth - this.padding.left - this.padding.right;
        },
        height() {
            return this.outerHeight - this.padding.top - this.padding.bottom;
        },
        ...mapState({
            starterId: state => state.starterId,
            range: state => state.range,
            color: state => state.color
        })
    },
    watch: {
        // selection(newVal, oldVal) {
        //     this.loadData(newVal.map(d => d.test_id));
        // }
    },
    methods: {
        // 通过list的选项显示曲线图
        getCurveById(id) {
            const url =
                'http://127.0.0.1:8000/api/starter/' +
                this.starterId +
                '/trend/' +
                id +
                '/' +
                this.selectedChannel +
                '/';

            this.$http
                .get(url)
                .then(res => {
                    this.lineData = res.data;
                })
                .catch(() => {
                    this.$Message.error('Get trend lineData failed!');
                });
        },
        changeChannel(channel) {
            this.selectedChannel = channel;
            this.renderAxis();
            this.renderBrush();
            this.loadData(this.selection.map(d => d.test_id))
        },
        initScales() {
            this.colorScale = d3
                .scaleOrdinal(d3.schemeCategory10)
                .domain(this.channels);

            this.rowScale = d3
                .scaleLinear()
                .range([0, this.width])
                .domain([1, 2000]);

            for (let key in this.channelScale) {
                if (this.channelScale.hasOwnProperty(key)) {
                    this.channelScale[key].range([this.height, 0]);
                }
            }

            this.xBrushScale = d3
                .scaleLinear()
                .range([0, this.width])
                .domain([1, 2000]);

            this.yBrushScale = d3
                .scaleLinear()
                .range([this.height, 0])
                .domain(this.channelScale[this.selectedChannel].domain());
        },
        initGenerator() {
            // 区域生成器
            this.areaGen
                .curve(d3.curveBasis)
                .x(d => this.rowScale(d.row_id))
                .y1(d => this.channelScale[this.selectedChannel](d.v_max))
                .y0(d => this.channelScale[this.selectedChannel](d.v_min));
            // 线条生成器
            this.lineGen
                .curve(d3.curveBasis)
                .x(d => this.rowScale(d.row_id))
                .y(d => this.channelScale[this.selectedChannel](d.v_avg));

            this.lineGen2
                .curve(d3.curveBasis)
                .x(d => this.rowScale(d.row_id))
                .y(d =>
                    this.channelScale[this.selectedChannel](
                        d[this.selectedChannel]
                    )
                );
            // this.areaGen
            //     .curve(d3.curveBasis)
            //     .x(d => this.xBrushScale(d.row_id))
            //     .y1(d => this.yBrushScale(d.v_max))
            //     .y0(d => this.yBrushScale(d.v_min));

            // this.lineGen
            //     .curve(d3.curveBasis)
            //     .x(d => this.xBrushScale(d.row_id))
            //     .y(d => this.yBrushScale(d.v_avg));
        },
        renderAxis() {
            // 定义坐标轴
            this.rowAxis = d3.axisBottom(this.rowScale);
            this.channelAxis = d3
                .axisLeft(this.channelScale[this.selectedChannel])
                .ticks(5);

            // 调用坐标轴
            d3.select(this.$refs.gRow).call(this.rowAxis);
            d3.select(this.$refs.gSpeed).call(this.channelAxis);
        },
        renderBrush() {
            const xBrush = d3
                .brushX()
                .extent([[0, 0], [this.width, this.brushWidth]])
                .on('brush end', () => {
                    const extent = d3.event.selection;
                    this.xBrushScale.domain([
                        this.rowScale.invert(extent[0]),
                        this.rowScale.invert(extent[1])
                    ]);
                    d3
                        .select(this.$refs.gRow)
                        .call(this.rowAxis.scale(this.xBrushScale));

                    this.transform.tx = this.xBrushScale(1);
                    this.transform.sx = this.width / (extent[1] - extent[0]);
                });
            const yBrush = d3
                .brushY()
                .extent([[0, 0], [this.brushWidth, this.height]])
                .on('brush end', () => {
                    const extent = d3.event.selection;
                    let range = this.channelScale[this.selectedChannel].domain();
                    this.yBrushScale.domain([
                        this.channelScale[this.selectedChannel].invert(
                            extent[1]
                        ),
                        this.channelScale[this.selectedChannel].invert(
                            extent[0]
                        )
                    ]);
                    d3
                        .select(this.$refs.gSpeed)
                        .call(this.channelAxis.scale(this.yBrushScale));

                    this.transform.ty = this.yBrushScale(range[1]);
                    this.transform.sy = this.height / (extent[1] - extent[0]);
                });

            d3
                .select(this.$refs.brushX)
                .call(xBrush)
                .call(xBrush.move, [0, this.width]);

            d3
                .select(this.$refs.brushY)
                .call(yBrush)
                .call(yBrush.move, [0, this.height]);
        },
        loadData(dataArr) {
            const url =
                'http://127.0.0.1:8000/api/starter/' +
                this.starterId +
                '/trend/';

            if (this.selection.length) {
                this.spinShow = true;

                this.$http
                    .post(
                        url,
                        {
                            channel: this.selectedChannel,
                            test_set: dataArr
                        },
                        {
                            emulateJSON: true
                        }
                    )
                    .then(res => {
                        this.data = res.data;
                    })
                    .catch(error => {
                        console.error(error);
                        this.$Message.error('趋势密度图数据获取失败');
                    })
                    .finally(() => {
                        this.spinShow = false;
                    });
            }
        }
    },
    created() {
        this.initScales();
        this.initGenerator();
    },
    mounted() {
        this.renderAxis();
        this.renderBrush();
        // this.loadData();
    }
};
</script>

<style lang="less">
div.trend {
    width: 100%;
    height: 100%;
    // .divideBar {
    //     width: 2px;
    //     height: 90%;
    //     margin-top: 30px;
    //     background-color: #c2c2c2;
    //     float: left;
    // }
    // .divideDash {
    //     stroke: #616161;
    //     stroke-width: 3px;
    //     stroke-dasharray: 8 5;
    // }
    // &__ctrl {
    //     width: 25%;
    //     height: 100%;
    //     float: left;
    //     // border: 1px solid black;
    //     background-color: #f5f7f9;
    //     // overflow: auto;
    //     &__form {
    //         height: 100%;
    //         width: 145px;
    //         float: left;
    //         padding: 5px 5px;
    //         .ivu-card-bordered {
    //             box-shadow: 2px 0 2px grey, -2px 0 2px grey;
    //         }
    //         .ivu-card-head {
    //             padding: 0;
    //             height: 40px;
    //             line-height: 40px;
    //             p {
    //                 height: 40px;
    //                 line-height: 40px;
    //                 font-weight: normal;
    //                 font-size: 12px;
    //                 text-align: left;
    //                 text-indent: 1em;
    //             }
    //         }
    //         .ivu-card-body {
    //             padding: 8px 5px;
    //             li {
    //                 text-align: left;
    //                 color: #88aaf3;
    //             }
    //         }
    //     }
    //     &__list {
    //         height: 100%;
    //         width: 175px;
    //         float: right;
    //         .list__header {
    //             width: 170px;
    //             height: 20px;
    //             margin-top: 5px;
    //             background-color: #eaffff;
    //             border-top-left-radius: 8px;
    //             border-top-right-radius: 8px;
    //             box-shadow: 2px 0 2px grey, -2px 0 2px grey;
    //             line-height: 20px;
    //             // text-align: left;
    //             // text-indent: 2em;
    //             // font-weight: bolder;
    //             // font-style: italic;
    //         }
    //         .list__body {
    //             width: 170px;
    //             height: 415px;
    //             background-color: white;
    //             border-top: 1px solid #c0c0c0;
    //             border-bottom-left-radius: 8px;
    //             border-bottom-right-radius: 8px;
    //             box-shadow: 2px 0 2px grey, -2px 0 2px grey;
    //             overflow: auto;
    //             .ivu-tree {
    //                 height: 100%;
    //                 ul {
    //                     text-align: left;
    //                     padding-left: 15px;
    //                     border-top: 1px solid #e2e2e2;
    //                 }
    //             }
    //             .ivu-tree-empty {
    //                 height: 100%;
    //                 line-height: 180px;
    //                 text-align: center;
    //                 color: #c0c0c0;
    //             }
    //         }
    //     }
    // }
    &__chart {
        width: 100%;
        height: 100%px;
        // float: left;
        position: relative;
    }
    svg {
        background-color: #ff008000;
        g.axis {
            font: 10px sans-serif;
            path,
            line {
                fill: none;
                stroke: #000;
                shape-rendering: crispEdges;
            }
        }
        g.legends {
            font-size: 12px;
            font-weight: bold;
        }
    }
    div.sng-tag {
        background-color: black;
        display: none;
        position: relative;
        right: 0;
        top: -400px;
        width: 100px;
        height: 100px;
    }
}
</style>
